This manual describes the use of Fuzzy Prolog version 3.0. This manual assumes that the reader is familiar with Prolog. If further information on Prolog is needed, refer to Programming in Prolog [Clocksin & Mellish, 1984]. If further information on the theory and operation of Fuzzy Prolog is desired, refer to the MS thesis Programming in Fuzzy Logic: Fuzzy Prolog [Richards, 1986].
Fuzzy Prolog is a dialect of Prolog based on fuzzy logic. In fuzzy logic truth values fall in a continuous range from false to true, represented by numbers in the real range 0 to 1. This is in contrast to Prolog, which is based on predicate logic where propositions must be either false or true. Predicate logic is a subalgebra of fuzzy logic, so Fuzzy Prolog encompasses all normal Prolog operations.
Fuzzy Prolog is based on Prolog as described in [Clocksin & Mellish, 1984], and on C-Prolog version 1.2a [Pereira]. Fuzzy Prolog also implements many of the lexical features of Ada. In order to develop a Fuzzy Prolog interpreter within the scope of a thesis effort, several Prolog features and built-in predicates were omitted. The additions to Prolog syntax required for fuzzy logic are minimal; Fuzzy Prolog will run normal Prolog programs with little or no change.
Differences from Prolog
Lexics
Fuzzy Prolog follows Ada lexical rules. This means, for instance, that identifiers must begin with letters (in Prolog identifiers may begin with certain nonalphabetic symbols). In this manual the term identifier refers to items which are valid predicate names (i.e. names beginning with lower case letters). Variable names follow the same lexical rules as identifiers but begin with capital letters. Identifiers and variable names are not normally case-sensitive (except for the first character, which distinguishes between the two). There is an alternate way of specifying identifiers, enclosing them in double quotes, which allows them to contain any sequence of characters. A double quote may be inserted by placing two consecutive double quotes (e.g. "double "" quote"). Identifiers delimited by double quotes are case sensitive.
Comment delimiters may either be the Ada double-dash '--' or the Pascal scroll brackets '{' and '}'. The Prolog format of '/*' and '*/' is not supported.
Names of built-in predicates in Fuzzy Prolog are strictly reserved by the interpreter, including those built-in predicates listed below which are not implemented in the current version. In Prolog, names of built-in predicates may be redefined by the user and may even appear as variables.
Finally, if a clause ends with an integer, there must be a space between the integer and the period ending the clause. Otherwise, the interpreter cannot determine whether it has reached the end of a clause, or whether the user has forgotten to place digits to the right of the decimal point on a floating point number. Naturally, if a clause ends with a floating point number there is no ambiguity, and this restriction is not necessary.
Types
Fuzzy Prolog explicitly supports character literals (e.g. 'a') and floating point numbers. The addition of these explicit types may complicate conversion of some Prolog programs. In Prolog, if the type of an item is deduced by elimination using predicates like var and atom, the logic may have to be changed in Fuzzy Prolog since more types are present. Further changes to the predicates used to determine types are discussed below.
Lists in Fuzzy Prolog cannot currently appear as arguments to comparison operators.
Operators
Fuzzy Prolog has five logic operators rather than three as in Prolog. The new operators are the bar '|' and the hat '^'. The semicolon ';' is implemented as defined herein (as a "max" operation on truth values) whereas in Prolog it represents an implicit backtrack choice.
All comparison operators will accept arithmetic expressions on either side (in Prolog, arithmetic expressions are allowed only on the right-hand side of is); this has the effect of making = and is identical. The operators <, =<, >, and >= work with numbers, characters, and identifiers (e.g. the identifier "abc" is less then the identifier "abd"). The is and = operators both create bindings when one of their arguments is an uninstantiated variable.
Predicates
There are several built-in predicates which are not present in Prolog. Predicates fuzzy and threshold are used to manipulate the current truth value and the search threshold; these terms are defined in the Syntax and Semantics chapter of this manual.
The predicate atomic is different from that in Prolog. In Fuzzy Prolog it returns true for all types except variables and lists, whereas in Prolog it returns true only for constants and integers. The built-in predicate consult will accept a series of files as arguments (e.g. consult(file1, file2, file3).
Predicate parse provides the user the ability to generate a listing of a Fuzzy Prolog program with embedded error messages. Predicate parse is used just like consult but rather than reading the file into the rule base and displaying error messages to the screen it parses the file and creates a listing file with the suffix .lst which contains the source listing and error messages. The parse predicate does not read the rules into the rule base.
The following Prolog predicates are not currently implemented in Fuzzy Prolog:
=.. clause display functor get get0
name nodebug nospy op org reconsult
see seeing seen spy tell telling
told
Fuzzy Prolog Operators
Fuzzy Prolog uses essentially the same operators as Prolog. Fuzzy Prolog includes two additional logic operators and adds flexibility to the comparison operators. In all cases except the ';' Fuzzy Prolog operators produce results identical to Prolog operators, though the reverse is not true. The ';' in Fuzzy Prolog performs a Fuzzy-OR of its operands, whereas in Prolog it represents an implicit backtrack choice.
Logic Operators The major functional difference between Fuzzy Prolog and ordinary Prolog is that Fuzzy Prolog is based on fuzzy logic rather than predicate logic. In fuzzy logic truth values are in the real range 0 to 1 rather than just false or true. Also, fuzzy logic uses five logic operators rather than the three (AND, OR, and NOT) used in predicate logic. These operators are the fuzzy AND (f-AND or ','), fuzzy OR (f-OR or ';'), probability AND (p-AND or '^'), probability OR (p-OR or '|'), and complement (NOT or 'not'). The three of these which use Prolog operator symbols (f-AND, f-OR, and complement) all produce the same results as Prolog operators when given nonfuzzy operands (i.e. 0 and 1).
The precedence of the logic operators is
; -- 254 , -- 253 -- 252 ^ -- 251
not -- 60
where lower precedence indicates earlier execution.
The f-AND is defined as
a f-AND b = min(a, b).
When used with nonfuzzy values, this operator produces the truth table
0 1 0 0 0 1 0 1
which is the same as the truth table for the predicate logic AND. Similarly, the f-OR and NOT are defined as
a f-OR b = max(a, b),
and
NOT a = 1 - a
respectively, and give the same results for nonfuzzy operands as do predicate logic operators.
The p-AND and p-OR are defined as
a p-AND b = a * b,
and
a p-OR b = a + b - a * b.
These operators have no equivalent in Prolog. The p-AND represents the probability that two independent events a and b will both occur. The p-OR represents the probability that either or both of the events will occur. These operators are used in the same way as the normal Prolog operators; e. g.
Fuzzy Prolog has the same set of comparison operators as Prolog, although they are defined somewhat differently. In all cases the Fuzzy Prolog operators will work with a program written for Prolog. The reverse, however, is not true. The most notable difference is that arithmetic operations may be carried out on either side of any comparison operator. This means that the "is" operator is no different from the "=" operator. The precedence of the comparison operators is
= -- 40 \= -- 40 == -- 40 \== -- 40
< -- 40 =< -- 40 >= -- 40 > -- 40
is -- 40
Since lower precedence indicates earlier execution, comparison operators will be executed before logic operators. When comparison operators succeed they return a truth value of 1. When they do not succeed they cause failure and backtracking.
Equal '='. The equal operator compares its operands and returns true if they have (or are bound to) the same value. If they have different values it returns false. If either or both of the operands is uninstantiated then the two operands are bound together and equal returns true.
Not equal '\='. The "not equal" operator is the complement of the equal operator. If the two operands have the same value it returns false. If they have different values it returns true. If one or both of the operands is uninstantiated (and hence they would be "equal"), it returns false. "Not equal" does not affect any variable bindings.
Equality '=='. The equality operator returns true if its operands have the same value, and false if they do not. If either operand is uninstantiated then, unless the operands are the same uninstantiated variable, the operands do not have the same value and equality returns false. If the operands are the same uninstantiated variable then equality returns true. Equality does not affect any variable bindings.
Not equality '\=='. The "not equality" operator is the complement of the equality operator. If the operands are equal it returns false. If they are different it returns true. If either operand is uninstantiated it returns true, unless the operands are the same uninstantiated variable in which case it returns false. This operator does not affect variable bindings.
Less or equal '=<'. This operator works on numbers, characters, and identifiers. It returns true if the left-hand operand is less than or equal to the right-hand operand, and false otherwise.
For characters and identifiers this represents a comparison of the ordinal value of the characters within the character set. This operator does not affect variable bindings.
Greater or equal '>='. This operator works on numbers, characters, and identifiers. It returns true if the left-hand operand is greater than or equal to the right-hand operand, and false otherwise. For characters and identifiers this represents a comparison of the ordinal value of the characters within the character set. This operator does not affect variable bindings.
Less than '<'. This operator works on numbers, characters, and identifiers. It returns true if the left-hand operand is less than the right-hand operand, and false otherwise. For characters and identifiers this represents a comparison of the ordinal value of the characters within the character set. This operator does not affect variable bindings.
Greater than '>'. This operator works on numbers, characters, and identifiers. It returns true if the left-hand operand is greater than the right-hand operand, and false otherwise. For characters and identifiers this represents a comparison of the ordinal value of the characters within the character set. This operator does not affect variable bindings.
Arithmetic comparison 'is'. In Fuzzy Prolog this operator is identical to the "equal" comparison operator. In Prolog this operator represents the only allowable time to perform arithmetic calculations for a comparison. In Fuzzy Prolog, arithmetic expressions are allowed as operands on either side of any comparison operator.
Arithmetic Operators
Fuzzy Prolog implements five arithmetic operators: +, -, *, /, and mod. Operands for these operators must be numeric. They may not be uninstantiated variables. The following predicates are examples of legal usage:
X is 7 * (3 + 4) mod 8 (X will be bound to 1)
4 * Y \== 8 (Y must have a value when '*' is executed)
7.0 =< 9.3
3 + 4 = X (X will be bound to 7)
The precedence of the arithmetic operators is
+ -- 31 - -- 31 * -- 21 / -- 21
mod -- 11
where lower precedence indicates earlier execution. Arithmetic operators are executed before comparison or logic operators. The definition of the arithmetic operators is self-evident.
Operation
Fuzzy Prolog was written in Ada under the Verdix Ada Development System running on a VAX 11/785 with Berkeley UNIX 4.2 BSD. For source or object code contact the Air Force Institute of Technology, Department of Electrical and Computer Engineering, Wright-Patterson Air Force Base, Ohio 45433.
The interpreter is invoked by typing fuzzy. It will initialize itself, display the current version number, and display the normal '?-' prompt. From this point using the Fuzzy Prolog interpreter is the same as using a Prolog interpreter; the user enters goals to be satisfied and Fuzzy Prolog attempts to resolve the goals within its rule base. As in Prolog, all user inputs must be terminated by a period. To leave the interpreter the user enters the single goal "halt."
Syntax and Semantics
Fuzzy Prolog resolves goals by using resolution and unification, just as Prolog does. In Prolog goals either succeed or fail; if they succeed resolution continues and if they fail backtracking occurs and another path in the search tree is tried. In Fuzzy Prolog, however, goals may return values other than false and true and the search process must account for this. To manage fuzzy truth values, the interpreter internally maintains two variables: the current truth value and the search threshold.
Current truth value
The current truth value at any point is the cumulative value of the predicates that have been resolved and the logic operators that have been executed. The truth value is initially set to 1. For example, if the user provides the goal a and the rule base contains the clause
a :- b, c.
the truth value begins at 1. If predicate b is resolved and returns the truth value 0.7, 0.7 will become the current truth value. If predicate c is resolved and returns the truth value 0.5 then the current truth value will become 0.5 since the comma represents the f-AND operation (which is defined as min(0.7, 0,5)). Since all predicates have now been resolved, this value will be returned as the certainty of the solution Fuzzy Prolog has found through this chain of resolution.
In some cases determining the current truth value may be less straightforward. In the clause
a :- b, c ^ d.
the precedence of the p-AND operator ('^') dictates that it be executed before the f-AND operator (','), even though the predicates are resolved left-to-right. As a result, after resolving predicate c the truth values of b and c cannot be combined; their truth values must be separately maintained until after d has been resolved. In cases like this, the most recently developed truth value (here the truth value of c) is the current truth value.
The current truth value may be accessed and manipulated via the built-in predicate fuzzy, which is defined later in this chapter.
Search Threshold
The search threshold in Fuzzy Prolog defines a criterion for the success or failure of searches. In Prolog backtracking is initiated when an attempted resolution fails. In Fuzzy Prolog backtracking is also initiated when the current truth value falls below a predefined search threshold.
The search threshold defaults to 0.1 and may range from 0 to 1. It is accessed and manipulated by the built-in predicate threshold.
Built-in Predicates
Fuzzy Prolog includes the following built-in predicates:
! asserta assertz atom atomic call
consult fail float fuzzy integer listing
ln log nl nonvar notrace number
parse put read repeat reset retract
tab threshold trace true var write
Note that halt, which is entered by the user to terminate Fuzzy Prolog, is neither a built-in predicate nor a reserved word.
Cut '!'. The cut in Fuzzy Prolog is identical to the cut in ordinary Prolog. It is used to limit backtracking by committing Prolog to all choices made in the current clause up to the point where the cut occurs.
asserta. The asserta predicate is used to add facts dynamically to the data base. It accepts one or two arguments: a functor which becomes the head of the fact and a fuzzy truth value which becomes the tail (a functor is an identifier which may optionally be followed by an argument list). If the second argument is not specified the fuzzy truth value defaults to 1. For example, if
asserta( alpha(A,B), 0.6 )
is encountered during program execution, it will add the fact
alpha(A,B) :- fuzzy(0.6).
to the data base. Facts added with asserta are inserted in the data base before any other clauses with the same name.
assertz. Predicate assertz is identical to asserta except that it adds facts after any other clauses with the same name.
atom. This predicate requires a single argument. It succeeds (i.e. returns a truth value of 1) if its argument is an identifier (i.e. a valid predicate name). For example, atom will return true in all the following clauses:
atom(alpha) atom(alpha(X, 13)) atom("hi there") A = alpha, atom(A)
It will fail in the following examples:
atom(A) (X is uninstantiated) atom(13) atom('c')
atomic. This predicate requires a single argument, and will return a truth value of 1 if that item is an identifier, character literal, integer number, or floating point number. It will fail if its argument is a list or an uninstantiated variable.
call. Predicate call takes a single argument, which must be a functor. It causes Fuzzy Prolog to resolve its argument as if that argument appeared in place of the call predicate. For example, the following statements are completely equivalent:
alpha(X,Y) call(alpha(X,Y))
The call predicate is generally used to call functors which have been bound to a variable, e.g. call(X) where X is bound to some functor. Note that variables appearing in a functor are lexically scoped (i.e. their values are taken from the clause in which the functor is defined). For example, in the program
a :- X = 3, b(alpha(X)). b(What) :- X = 4, call(What). alpha(Num) :- write(Num), nl.
a call to a will write the number 3--not the number 4.
consult. The consult predicate is used to read in one or more files of Fuzzy Prolog clauses. These clauses are added to the beginning of the rule base. Filenames are given as constants, e.g.
consult(file1, file2, file3).
Fuzzy Prolog translates identifiers to all upper case, so the file names given above would actually refer to FILE1, FILE2, and FILE3. If this is not desirable, or if the file names contain characters not normally allowed in identifiers, then the file names should be enclosed in double quotes. File names in quotes may be pathnames.
fail. Predicate fail causes immediate failure and backtracking.
float. Predicate float takes a single argument. It succeeds if its argument is a floating point number, and fails otherwise.
fuzzy. The built-in predicate fuzzy sets and accesses fuzzy truth values. It may appear anywhere as an antecedent to a clause. It accepts a single argument, which must either have a floating point value or be an uninstantiated variable. The clauses
If the argument to fuzzy is an uninstantiated variable, the variable is instantiated to the current truth value. Additionally, fuzzy returns the current truth value as the truth value of its resolution. This means that, if fuzzy is connected to other predicates with the f-AND or the f-OR operator, it will not change the current truth value (since min(a,a) = a and max(a,a) = a). Calling fuzzy with a variable allows a program to access the current truth value and use it in calculations or to direct future actions.
If the argument to fuzzy has a floating point value, fuzzy returns this value as the truth value of its resolution. This is the only way of introducing fuzzy truth values into the resolution process since predicate resolution and the comparison operators always either succeed or fail. If fuzzy is the only antecedent in a clause then the clause is a special type of fact; i.e. a fact with a fuzzy truth value. For example
alpha :- fuzzy(0.7).
causes the predicate alpha to have a fuzzy truth value of 0.7.
If fuzzy is called with an uninstantiated variable, it sets that variable to the current truth value, and returns with its own truth value set to the current truth value. Note that the current truth value depends heavily on the order of evaluation of the surrounding operators as determined by operator precedence or parentheses. For example, in the clause
alpha :- fuzzy(0.7), true ^ fuzzy(X).
fuzzy will set X to 1.0 since that is the value returned by "true" and the precedence of the p-AND causes it to be executed before the f-AND. Similarly, if fuzzy is within parentheses then its truth value will only be taken from other predicates and operators in the parentheses. The following clause will instantiate X to the lower value of "b" or "c":
f :- a, (b, c, fuzzy(X), d), e.
On the other hand,
alpha :- beta, delta, fuzzy(X), gamma.
will set X to the lesser of the values returned by beta and delta, since normal execution is left to right and the precedence of the operators does not interfere with this.
integer. Predicate integer takes a single argument. It succeeds if its argument is an integer number, and fails otherwise.
listing. This predicate takes a single functor as its argument. It displays a list of all clauses in the rule base which have as their head a predicate with the same name as the functor it received as an argument. The number of arguments the functor has is irrelevant. The listing produced has a somewhat different format from user-generated source code.
ln. Predicate ln takes two arguments. The first argument is a number and the second argument is the natural logarithm of that number. Either argument may be uninstantiated; this predicate will therefore perform both natural logarithms and exponentiation.
log. Predicate log takes two arguments. The first argument is a number and the second argument is the base 10 logarithm of that number. Either argument may be uninstantiated; this predicate will therefore perform both logarithms and exponentiation.
nl. The "nl" predicate generates a new line by sending an end- of-line character (carriage return) to the current output device.
nonvar. Predicate nonvar takes a single argument and returns true if that argument is anything except an uninstantiated variable. If the argument is an uninstantiated variable nonvar fails.
notrace. Notrace turns off the trace feature. See "trace" for further information.
number. This predicate accepts a single argument. It returns true if that argument is either an integer or a floating point number, and fails otherwise.
parse. Predicate parse is used like consult. However, rather than reading a Fuzzy Prolog program into the rule base, parse generates a listing file. This is useful when initially writing a program since error messages are embedded in the listing file rather than displayed to the screen. The listing file has the same name as the source file plus the suffix ".lst". Parse does not add rules to the data base.
put. Predicate put takes a single argument, which must be an integer in the ordinal range of the character set. It writes the corresponding character to the current output device. For example, put(65) would print an 'A'.
read. Read requires one argument. It prompts the user for input, and attempts to unify its argument with the next term read from the keyboard. If its argument is an uninstantiated variable it will be set to the term read from the keyboard; otherwise it will simply be matched against it. If unification succeeds then read returns true, otherwise it returns false.
repeat. This predicate is used to generate multiple solutions through backtracking. Most built-in predicates will fail when backtracking attempts to resatisfy them. This predicate will succeed any number of times. Hence, it represents an infinite loop which may only be exited by the cut.
reset. Completely erases and reinitialized the rule base.
retract. The retract predicate takes a functor as its argument and removes from the rule base the first clause whose head unifies with this functor (unification includes the functor arguments). It is the counterpart of asserta and assertz.
tab. This predicate requires a single argument which must be an integer. It prints the requested number of spaces to the current output device.
threshold. The built-in predicate threshold sets and accesses search threshold values. If, during resolution, the current truth value falls below the current search threshold, resolution fails and backtracking occurs. Predicate threshold may appear anywhere as an antecedent to a clause, and the threshold it defines takes effect from that point in the clause (resolution proceeds strictly left-to- right within a clause). It accepts a single argument, which must either have a floating point value or be an uninstantiated variable. The clauses
all show legal uses of threshold. This predicate always returns with its own truth value of 1.
In other words, If the user wishes to continue processing as long as the truth value remains 0.5 or higher, then threshold should be called with a value of 0.5. If a clause needs to know what the current threshold is, it calls threshold with an uninstantiated variable.
Predicate threshold defines a local level of success, not a global one. When a clause defines a threshold, this threshold applies to the remainder of that clause, and to any other clauses which it invokes through resolution. The threshold will not affect higher-level clauses. This may be likened to the visibility rules for variables in Pascal or Ada, where a variable is visible to the procedure in which it is defined and all its subprocedures but is not visible outside the procedure. For instance, if rule base contains
and the user introduces the goal alpha, the threshold set in beta will apply to beta and gamma (since gamma is a goal introduced by beta). However, the threshold will not propagate upward into alpha and delta.
Limiting search thresholds to local effects allows a predicate to control backtracking for its operations without causing unexpected side-effects for higher level predicates (which have no insight into its workings). If the threshold were global, then a predicate might find its searches failing because its search threshold was altered by some predicate which it called.
If a clause does not define its own threshold, its threshold will be taken to be the one currently in effect. If it does define one, then the threshold it defines will hold for it and all predicates which it calls (unless those predicates in turn define their own local thresholds). For example, the rules
a :- threshold(0.5), b, c. b :- threshold(0.7), d. c. d.
will result in clauses a and c using a threshold of 0.5. However, b defines its own threshold of 0.7, so b and d will use this value.
If threshold is called with an uninstantiated variable, it sets the variable to the value of the threshold currently in effect. This allows clauses to base their threshold on the one in effect when they are called.
trace. This predicate turns on the trace mode. Each time a predicate is called, trace will print the current truth value and the values of all arguments on entry to the predicate. When the predicate returns, trace prints its truth value, the values of all its arguments, and the new current truth value. Trace cannot intercept the actions of comparison operators.
After each trace output, Fuzzy Prolog waits for the user to enter a trace command. Hitting a carriage return will continue program execution. A question mark will print a menu of valid trace commands. The valid commands are:
return, space, or Continue -- continue execution Abort -- abort current proof Bindings -- print variable bindings Fail -- fail current goal Goals -- print goal tree Help or ? -- print help menu Notrace -- turn off trace mode Truth -- print current truth/threshold
Commands may be selected by entering just their first character.
true. This predicate returns a truth value of 1.0. This predicate is never needed, but it occasionally helps make a program more readable.
var. Predicate var takes a single argument. It returns true if this argument is an uninstantiated variable, and fails otherwise.
write. Prints the value of its single argument to the current output device.
Formal Syntax
Fuzzy Prolog syntax is based on Prolog as described in [Clocksin & Mellish, 1984]. Fuzzy Prolog also implements many of the lexical features of Ada. The additions to Prolog syntax required for fuzzy logic are minimal; Fuzzy Prolog will run normal Prolog programs with little change.
The following paragraphs define the syntax of Fuzzy Prolog in Backus-Naur form (BNF), beginning with basic lexical elements and building up to the syntax of clauses. The features of Fuzzy Prolog are discussed at each step.
Basic definitions
Identifiers in Fuzzy Prolog consist of letters, numbers, and underlines. Numbers may contain digits or underlines; which digits are valid depends on the base of the number.
upper_case_letter ::= A B C . . . W X Y Z lower_case_letter ::= a b c . . . w x y z num_digit ::= 0 1 2 3 . . . 7 8 9 alpha_digit ::= A a B b . . . E e F f underline ::= _
digit ::= num_digit alpha_digit letter ::= upper_case_letter lower_case_letter name_character ::= letter digit underline number_character ::= digit underline
Note that the comment delimiters in Fuzzy Prolog are different from those in Prolog. In Fuzzy Prolog comments may be placed at the end of a line by using the Ada double-dash, or blocks of comments may be delimited by the scroll-brackets. Block comment delimiters may be nested; this may arise, for example, if an entire block of code is commented out. The Prolog delimiters '/*' and '*/' are not supported.
Lexical elements
The lexical rules below define Fuzzy Prolog identifiers, variables, numbers, and character literals. These basic elements can be used to build lists. Any of these items including lists may appear as arguments to predicates.
constant ::= identifier [ ( argument {, arguments} ) ] number character_literal term ::= variable constant term ::= ( term {arithmetic_operator term} ) item ::= variable constant list list ::= '[' [ item { , item } ['|' item] ] ']' argument ::= item list
Identifiers are sequences of letters, digits, and underlines which begin with a lower-case letter. Underlines may not begin or end an identifier or be adjacent to each other. Identifiers may be names of built-in predicates (reserved words) or user-defined names. Variables are sequences of letters, digits, and underlines which begin with an upper-case letter, except for the anonymous variable (where the underline is the only character present). Case is not normally significant in identifiers except for the first letter, which determines whether or not an identifier is a variable. However, an identifier can be specified in double-quotes. Identifiers specified in this way can contain any sequence of characters, which will be used exactly as specified (i.e. case will be significant). To embed a double quote, two consecutive double quotes are used (e.g. "double "" quote").
Numbers may be integer or floating point. Floating point numbers must contain a decimal point with at least one digit on each side. Numbers may be specified in any base between 2 and 16 inclusive by using the based notation; the base itself is always given in base 10. Numbers may contain underlines, but the underlines must separate digits; they cannot begin or end the number or appear next to the base character ('#') or the decimal point. The digits valid in a number depend on its base. If base is not specified, the number is assumed to be decimal (base 10).
Character literals are single characters enclosed in single quotes. Lists are ordered collections of items (possibly including other lists). The beginning and ending of a list are marked by square brackets ('[' and ']'). Elements within a list are separated by commas, except for the final element which may be preceded by a vertical bar ('|') and is then referred to as the tail of the list.
Prolog defines a special element called a functor, which is a predicate complete with arguments (e.g. in asserta(alpha(A,B)) both asserta and alpha are functors). In Fuzzy Prolog no distinction is drawn between identifiers and identifiers with arguments, so functors are valid anywhere identifiers are valid. When a functor is passed as an argument to another predicate, it is important to remember that any variables it contains are lexically scoped. See the discussion under the call predicate for more information.
Arguments to predicates may consist of any of the items defined in this section.
The Fuzzy Prolog parser reserves the names of all built-in predicates including those which are not implemented. This allows easy addition of these predicates at a later time, and avoids confusion by preventing the user from choosing identifier names which conflict with predicates normally defined in Prolog interpreters.
Operators
The following operators are implemented in Fuzzy Prolog with the precedence shown (lower precedence indicates earlier execution):
; -- 254 , -- 253 -- 252 ^ -- 251
not -- 60 = -- 40 \= -- 40 == -- 40
\== -- 40 < -- 40 =< -- 40 >= -- 40
> -- 40 is -- 40 - -- 31 + -- 31
* -- 21 / -- 21 mod -- 11
These operators are broken into three classes as follows:
arithmetic_operator ::= + - * / mod comparison_operator ::= = \= == \== =< >= < > is logic_operator ::= , ; ^ not
Arithmetic operators may only be used to calculate the operands for comparison operators. Arithmetic operators may appear on either side of any comparison operator; however, all arguments to arithmetic operators must have values (they cannot be uninstantiated variables). This allows more flexibility than normal Prolog, where arithmetic expressions may only appear on the right-hand side of the is operator.
Since performing arithmetic matching is the only distinguishing feature of is in Prolog, the is operator in Fuzzy Prolog is functionally identical to the '=' operator. In Fuzzy Prolog, any comparison operator can compare any two items and generate a truth value of 0 or 1 depending on the particular matching function being used (for specific definitions of the comparison operators see appendix D). The is and = operators will create a variable binding when one of their operands is an uninstantiated variable, just as in Prolog.
Logic operators operate on truth values, and the result of a logic operator is itself a truth value. The logic operators implement the operations of fuzzy logic as defined in chapter II, where ';' is the f-OR, ',' is the f-AND, '|' is the p-OR, '^' is the p-AND, and not is the NOT operation.
Fuzzy Prolog does not support user-defined operators.
Syntactic elements
Fuzzy Prolog clauses are built of predicates joined by logic operators. Predicates may be user defined identifiers, built-in predicates (see above), or any operator/operand set which yields a truth value as its result (e.g. comparison operators).
special ::= univ comparison predicate ::= name [( argument {, argument} )] special built_in_predicate predicate ::= ( predicate {logic_operator predicate} )
body ::= predicate {logic_operator predicate} head ::= predicate clause ::= head [:- body] .
The univ predicate was defined earlier as a built-in predicate which is not implemented. Its syntax is specified here since it should be implemented if the Fuzzy Prolog interpreter is enhanced to be a production quality tool.
Further Information
If further information on Fuzzy Prolog is needed, there are three possible sources:
1) The documents in the bibliography, especially [Richards, 1986].
2) The Air Force Institute of Technology, Department of Electrical and Computer Engineering, Wright-Patterson Air Force Base, Ohio 45433.
3) The author. Capt Bradley L. Richards may be reached at 3813 Espejo NE, Albuquerque, NM 87111.
Bibliography
Clocksin, W. F. and C. S. Mellish. Programming in Prolog (Second Edition). Berlin: Springer-Verlag, 1984. Pereira, Fernando (editor). C-Prolog User's Manual Version 1.2a. SRI International, Menlo Park, California, undated. Richards, Bradley L., Programming in Fuzzy Logic: Fuzzy Prolog. MS thesis. School of Engineering, Air Force Institute of Technology (AU), Wright-Patterson AFB, Ohio, December 1986.